package com.learn.api.gateway.filters;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;

/**
 * @author lwt<br>
 * @description <br>
 * @date 2020/8/17
 */
@Slf4j
public class ConfigGatewayFilterFactory extends AbstractGatewayFilterFactory<ConfigGatewayFilterFactory.Config> {

    private static final String ELAPSED_TIME_BEGIN = "elapsedTimeBegin";
    private static final String KEY = "printTestInfo";


    public List<String> shortcutFieldOrder() {
        return Arrays.asList(KEY);
    }

    public ConfigGatewayFilterFactory() {
        //这里注意一下，一定要调用一下父类的构造器把 Config 类型传过去，否则会报 ClassCastException
        super(Config.class);
    }

    public GatewayFilter apply(Config config) {
        // 通过这种工厂创建出来的过滤器是没有指定order的，会被默认设置为是0，配置在yml文件中，则按照它书写的顺序来执行
        // 如果需要order 则这里修改为实现 GatewayFilter, Ordered 接口的类即可
        return (exchange, chain) -> {
            exchange.getAttributes().put(ELAPSED_TIME_BEGIN, System.currentTimeMillis());
            return chain.filter(exchange).then(
                    Mono.fromRunnable(() -> {
                        Long startTime = exchange.getAttribute(ELAPSED_TIME_BEGIN);
                        if (startTime != null) {
                            StringBuilder sb = new StringBuilder(exchange.getRequest().getURI().getRawPath())
                                    .append(": ")
                                    .append(System.currentTimeMillis() - startTime)
                                    .append("ms");
                            if (config.isPrintTestInfo()) {
                                log.info("----this is a test info!!");
                            }
                            log.info(sb.toString());
                        }
                    })
            );
        };
    }


    public static class Config {

        private boolean printTestInfo;

        public boolean isPrintTestInfo() {
            return printTestInfo;
        }

        public void setPrintTestInfo(boolean printTestInfo) {
            this.printTestInfo = printTestInfo;
        }

    }
}
